package com.sunny.controller;

import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.sunny.model.LoginLog;
import com.sunny.model.User;
import com.sunny.query.UserQuery;
import com.sunny.querybean.LoginLogQuery;
import com.sunny.service.ILoginLogService;
import com.sunny.service.IUserService;

import framework.FrameworkConstans;
import framework.ThreadLocalUser;
import framework.base.BaseController;
import framework.interceptors.AuthPassport;
import framework.interceptors.NoNeedInterceptor;
import framework.utils.CookieUtils;
import framework.utils.MD5Utils;
import framework.utils.NetworkUtils;

@Controller
@RequestMapping("/login")
public class LoginController extends BaseController implements NoNeedInterceptor {
	private static final Log log = LogFactory.getLog(LoginController.class);

	private static Map<String, HttpSession> onlineSessionMap = new ConcurrentHashMap<String, HttpSession>();

	@Resource
	ILoginLogService loginLogService;

	@Resource
	IUserService userService;

	@RequestMapping("login")
	@ResponseBody
	@AuthPassport(description = "liquan")
	public Map<String, Object> login(HttpServletRequest request, HttpServletResponse response) {
		String msg = "";
		UserQuery bq = parseForm(UserQuery.class, request);
		String isUserIdRemember = (String) request.getParameter("isUserIdRemember");
		CookieUtils cookieUtils = new CookieUtils(request, response);
		if ("true".equals(isUserIdRemember)) {
			cookieUtils.addCookie(FrameworkConstans.IS_COOKIE_REMENBER, isUserIdRemember);
			cookieUtils.addCookie(FrameworkConstans.COOKIE_USER_ID, bq.getUserId());
		} else {
			cookieUtils.deleteCookie(FrameworkConstans.IS_COOKIE_REMENBER);
			cookieUtils.deleteCookie(FrameworkConstans.COOKIE_USER_ID);
		}
		Map<String, Object> map = new HashMap<String, Object>();
		UsernamePasswordToken token = new UsernamePasswordToken(bq.getUserId(), MD5Utils.encodeUseSalt(bq.getPassword(), bq.getUserId()));
		token.setRememberMe(true);
		Subject subject = SecurityUtils.getSubject();
		try {
			subject.login(token);
			if (subject.isAuthenticated()) {
				request.getSession().setAttribute("user", bq);

				map.put(RESULT, SUCCESS);
				HttpSession session = request.getSession(true);
				LoginLogQuery lq = new LoginLogQuery();
				lq.setUserId(bq.getUserId());
				lq.setStatus(1);
				List<LoginLog> logList = loginLogService.selectList(lq, null);
				for (LoginLog loginLog : logList) {
					String sessionId = session.getId();
					if (loginLog != null && StringUtils.isNotEmpty(loginLog.getSessionId())) {
						if (!sessionId.equals(loginLog.getSessionId()) && loginLog.getStatus() == 1) {
							loginLog.setStatus(2);
							loginLogService.update(loginLog);
							HttpSession onlineSession = onlineSessionMap.get(loginLog.getSessionId());
							removeSessionAttribute(onlineSession);
						}
					}
				}
				setSessionAttribute(session, bq);
				userService.updateFailTimeByUserId(bq.getUserId(),true);	
				 

				LoginLog log = new LoginLog();
				log.setUserId(bq.getUserId());
				log.setSessionId(session.getId());
				log.setIp(NetworkUtils.clientIp());
				Date now = new Date();
				log.setActiveTime(now);
				log.setStatus(1);
				log.setLoginTime(now);
				loginLogService.insert(log);
				map.put("userId", bq.getUserId());

			}
		} catch (IncorrectCredentialsException e) {
			msg = "登录密码错误. 连续输错5次将被冻结 ";
			userService.updateFailTimeByUserId(bq.getUserId(),false);		 
			map.put(RESULT, FAIL);
			map.put(ERROR, msg);
		}  catch (LockedAccountException e) {
			msg = "帐号已被锁定. The account for username " + token.getPrincipal() + " was locked.";
			map.put(RESULT, FAIL);
			map.put(ERROR, msg);
		} catch (DisabledAccountException e) {
			msg = "帐号已被冻结 ";
			map.put(RESULT, FAIL);
			map.put(ERROR, msg);
		} catch (ExpiredCredentialsException e) {
			msg = "帐号已过期. the account for username " + token.getPrincipal() + "  was expired.";
			map.put(RESULT, FAIL);
			map.put(ERROR, msg);
		} catch (UnknownAccountException e) {
			msg = "帐号不存在. There is no user with username of " + token.getPrincipal();
			map.put(RESULT, FAIL);
			map.put(ERROR, msg);
		} catch (UnauthorizedException e) {
			msg = "您没有得到相应的授权！" + e.getMessage();
			map.put(RESULT, FAIL);
			map.put(ERROR, msg);
		}
		return map;
	}

	@RequestMapping("loginOut")
	@ResponseBody
	public Map<String, Object> loginOut(HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(RESULT, SUCCESS);
		HttpSession session = request.getSession();
		User user = ThreadLocalUser.currentUser();
		if (user == null) {
			return map;
		}
		LoginLog log = new LoginLog();
		log.setUserId(user.getUserId());
		log.setSessionId(session.getId());
		log.setStatus(2);
		log.setLogoutTime(new Date());
		loginLogService.loginOut(log);
		SecurityUtils.getSubject().logout();
		return map;
	}

	@RequestMapping("noLogin")
	public ModelAndView noLogin(HttpServletRequest request, HttpServletResponse response) {
		Map<String, String> map = new HashMap<String, String>();
		CookieUtils cookieUtils = new CookieUtils(request, response);
		String userName = cookieUtils.getCookieValue(FrameworkConstans.COOKIE_USER_ID);
		String isUserIdRemember = cookieUtils.getCookieValue(FrameworkConstans.IS_COOKIE_REMENBER);
		map.put("userId", userName);
		map.put("isUserIdRemember", isUserIdRemember);

		ModelAndView mv = new ModelAndView("/login", map);
		return mv;
	}

	@RequestMapping("index")
	public ModelAndView idnex(HttpServletRequest request, HttpServletResponse response) {
		response.setStatus(1000);
		return new ModelAndView("/login-noLogin");
	}

	private void removeSessionAttribute(HttpSession session) {
		if (session == null)
			return;

		String sessionId = session.getId();
		if (onlineSessionMap != null && onlineSessionMap.containsKey(sessionId))
			onlineSessionMap.remove(sessionId);

		try {
			Enumeration enumeration = session.getAttributeNames();
			while (enumeration.hasMoreElements()) {
				String attribute = (String) enumeration.nextElement();
				session.removeAttribute(attribute);
			}
		} catch (Exception e) {
			log.error("", e);
		}
	}

	private void setSessionAttribute(HttpSession session, User user) {
		try {
			session.setAttribute(FrameworkConstans.USER_SESSION, user);
			onlineSessionMap.put(session.getId(), session);
			ThreadLocalUser.setUser(user);
		} catch (Exception e) {
			log.error("", e);
		}
	}
}
